﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
#include<map>
#include<set>
#include<stdio.h>
#include <string>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
//#include <direct.h>//f linux
using namespace std;
#define DN 64//硬盘块数量
#define DBLOCK 256//256B

string basedir = "D:/temp/temp/";
bool usedBlock[DN];
string basedir = "/home/linhui/Documents/temp/";  //linux
//string basefile = basedir + "files.data";
//fstream iofile(basedir+"disk.data", ios::in | ios::out );
FILE* iof = fopen((basedir + "disk.data").c_str(),"rb+");
char buff[DBLOCK + 2];
struct inode {
	int id;//key
	string name;//文件名
	int i_count; //引用计数
	int size; //文件大小
	int di_mode = 777; //存取权限
	string owner;//文件主人
	int d_n=0;//使用硬盘块数量
	int dsets[DN];//硬盘块顺序
	long long d_set=0;//使用的硬盘块
};
struct direct//目录
{
	string d_name = ""; //目录名
	int d_ino; //目录号
	int n;//文件数量
	set<int>files_inodeid;//目录下文件inode
};
direct nowusr;
map<string, string>usrs;
map<int, inode>inodes;
map<string, direct>directs;
void initdisk()
{
	for (int i = 0; i < DN; i++)
	{
		//iofile.write(buff, DBLOCK);
		fwrite(buff, DBLOCK,1, iof);
	}
}
int getBlock()
{
	for (int i = 0; i < DN; i++)
	{
		if (usedBlock[i] == 0)return i;
	}
	return -1;
}
void freedisk(long long set)
{
	for (int i = 0; i < DN; i++)
	{
		if (set % 2 == 1)
		{
			usedBlock[i] = 0;
		}
		set /= 2;
	}
}
string readdisk(long long set)
{
	string re = "";

	for (int i = 0; i < DN; i++)
	{
		if (set % 2 == 1)
		{
			//iofile.seekg(i * DBLOCK, ios::beg);
			//iofile.read(buff, DBLOCK);
			fseek(iof, i * DBLOCK, SEEK_SET);
			fread(buff, 1, DBLOCK,  iof);
			string st2(buff, buff + DBLOCK);
			re += st2;
		}
		set /= 2;
	}
	return re;
}

long long writedisk(string instr)
{
	long long set = 0;
	int j = 0;
	while (j <= instr.length())
	{
		for (int i = 0; i < DBLOCK; i++)
		{
			if (j < instr.length())buff[i] = instr[j];
			else buff[i] = '\0';
			j++;
			
		}
		int tb = getBlock();
		if (tb == -1)
		{
			freedisk(set);
			cout << "error no enough disk" << endl;
			return 0;
		}
		usedBlock[tb] = 1;
		set += (1L << tb);
		//iofile.seekg(tb * DBLOCK, ios::beg); 
		//iofile.write(buff, DBLOCK);
		if (fseek(iof, tb * DBLOCK, SEEK_SET) != 0)cout<<111;
		fwrite(buff, 1, DBLOCK,  iof);
	}
	return set;
}
void savemap()//将map数据存下
{
	ofstream fout(basefile);
	fout << usrs.size() << endl;
	for (map<string, string>::iterator item = usrs.begin(); item != usrs.end(); item++)
	{
		string key = item->first;
		string val = item->second;
		fout << key << endl;
		fout << val << endl;
	}
	fout << inodes.size() << endl;
	for (map<int, inode>::iterator item = inodes.begin(); item != inodes.end(); item++)
	{
		int key = item->first;
		inode val = item->second;
		fout << key << endl;
		fout << val.id << endl;
		fout << val.name << endl;
		fout << val.i_count << endl;
		fout << val.size << endl;
		fout << val.di_mode << endl;
		fout << val.owner << endl;
		fout << val.d_n << endl;
		fout << val.d_set << endl;
	}
	fout << directs.size() << endl;
	for (map<string, direct>::iterator item = directs.begin(); item != directs.end(); item++)
	{
		string key = item->first;
		direct val = item->second;
		fout << key << endl;
		fout << val.d_name << endl;
		fout << val.d_ino << endl;
		fout << val.n << endl;
		for (set<int>::iterator it = val.files_inodeid.begin(); it != val.files_inodeid.end(); it++)
		{
			fout << *it << endl;
		}
	}
	long long set = 0;
	for (int i = 0; i < DN; i++)
	{
		if (usedBlock[i])
		{
			set += (1L << i);
		}
	}
	fout << set << endl;
	fout.close();
}
void initmap()//初始化map
{
	ifstream fin(basefile);
	int size;
	;
	string key, val;
	if (!(fin >> size&&size!=0))initdisk();
	for (int i = 0; i < size; i++)
	{
		fin >> key >> val;
		usrs[key] = val;
	}
	fin >> size;
	int keyi;
	inode valn;
	for (int i = 0; i < size; i++)
	{
		fin >> keyi;
		fin >> valn.id;
		fin >> valn.name;
		fin >> valn.i_count;
		fin >> valn.size;
		fin >> valn.di_mode;
		fin >> valn.owner;
		fin >> valn.d_n;
		fin >> valn.d_set;
		inodes[keyi] = valn;
	}
	fin >> size;
	direct vald;
	for (int i = 0; i < size; i++)
	{
		fin >> key;
		fin >> vald.d_name;
		fin >> vald.d_ino;
		fin >> vald.n;
		int tt;
		for (int j = 0; j < vald.n; j++)
		{
			fin >> tt;
			vald.files_inodeid.insert(tt);
		}
		directs[key] = vald;
	}
	long long set;
	fin >> set;
	for (int i = 0; i < DN; i++)
	{
		if (set % 2 == 1)usedBlock[i] = 1;
		else usedBlock[i] = 0;
		set /= 2;
	}
}
int getPower(inode file , int qx)//获取文件读写或执行权限，qx读4 写2 执行1
{
	if (file.owner == nowusr.d_name)
	{
		if ((file.di_mode / 100 % 10) & qx)return 1;
		else return 0;
	}
	if (0)//同组，未完成用户组功能，此处待重写
	{
		if ((file.di_mode / 10 % 10) & qx)return 1;
		else return 0;
	}
	if ((file.di_mode / 1 % 10) & qx)return 1;
	else return 0;
}
int getInodeId()//获取一个新的iNode id
{
	for (int i = 0;; i++)
	{
		if (inodes.find(i) == inodes.end())return i;
	}
	return -1;
}
void createusr(string name, string pwd)//新建用户
{
	if (usrs.find(name) != usrs.end())
	{
		cout << "this usr has been created" << endl;
		return;
	}
	usrs[name] = pwd;
	//_mkdir((basedir + name).c_str());
	mkdir((basedir + name).c_str(), 0777);  //linux
	direct dirt;
	dirt.d_ino = 0;
	dirt.d_name = name;
	dirt.n = 0;
	directs[name] = dirt; 
	cout << "create success" << endl;
}
void login(string name, string pwd)//登录
{
	if (usrs.find(name) == usrs.end())
	{
		cout << "no such login name" << endl;
		return;
	}
	if (usrs[name] == pwd)
	{
		nowusr = directs[name];
		cout << "login succeed" << endl;
	}
	else
	{
		cout << "login fail password wrong" << endl;
	}
}
void dir()//dir指令，列出当前目录下文件
{
	if (nowusr.d_name == "")
	{
		cout << "please login\nusrs list:" << endl;
		for (map<string, string>::iterator item = usrs.begin(); item != usrs.end(); item++)
		{
			string key = item->first;
			cout << key << endl;
		}
		return;
	}
	for (set<int>::iterator it = nowusr.files_inodeid.begin(); it != nowusr.files_inodeid.end(); it++)
	{
		int key = *it;
		cout << inodes[key].name << "\t\t" << nowusr.d_name + "/" + inodes[key].name << "\t\t"
			<< inodes[key].di_mode << "\t\t" << inodes[key].size 
			<< "Byte" << "\t\t" << inodes[key].owner << endl;
	}
}
void fcreate(string filename)//创建新文件
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}
	int key = -1;
	for (set<int>::iterator it = nowusr.files_inodeid.begin(); it != nowusr.files_inodeid.end(); it++)
	{
		if (inodes[*it].name == filename)
		{
			
			key = *it;
			break;
		}
	}
	if (key != -1)
	{
		cout << "error: file has been created" << endl;
		return;
	}
	string dir = basedir + nowusr.d_name + "/" + filename;
	fstream _file;
	_file.open(dir, ios::in);
	if (_file)
	{
		cout << "error: file has been created " << endl;
		return;
	}
	ofstream fout(dir);//创建文件
	if (!fout)
	{
		cout << "error: cant create " + dir << endl;
		return;
	}
	inode ti;
	ti.size = 0;
	ti.i_count = 1;
	ti.name = filename;
	ti.id = getInodeId();
	ti.di_mode = 777;
	ti.owner = nowusr.d_name;
	inodes[ti.id] = ti;
	directs[nowusr.d_name].n++;
	directs[nowusr.d_name].files_inodeid.insert(ti.id);
	nowusr = directs[nowusr.d_name];
	cout << "create success" << endl;
}
void fdelete(string filename)//删除文件
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}
	string dir = basedir + nowusr.d_name + "/" + filename;
	
	for (set<int>::iterator it = nowusr.files_inodeid.begin(); it != nowusr.files_inodeid.end(); it++)
	{
		int key = *it;
		if (inodes[key].name == filename)
		{
			if (getPower(inodes[key], 2) == 0)
			{
				cout << "delete fail,you dont have power" << endl;

				return;
			}
			long long lt = inodes[key].d_set;
			directs[nowusr.d_name].files_inodeid.erase(key);
			inodes.erase(key);
			nowusr = directs[nowusr.d_name];
			for (int i = 0 ; i < DN ; i++)
			{
				if (lt % 2 == 1)
				{
					usedBlock[i] = 0;
				}
				lt /= 2;
			}
			cout << "delete success" << endl;
			break;
		}
	}
	if (remove(dir.c_str()) != 0)

	{
		cout << "delete fail" << endl;
		return;
	}
}
void myfopen(string filename)//打开文件，未实现
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}

}
void mfclose(string filename)//关闭文件，未实现
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}

}
void myfread(string filename)//读文件
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}
	int key = -1;
	for (set<int>::iterator it = nowusr.files_inodeid.begin(); it != nowusr.files_inodeid.end(); it++)
	{
		if (inodes[*it].name == filename)
		{
			key = *it;
			if (getPower(inodes[key], 4) == 0)
			{
				cout << "read fail,you dont have power" << endl;
				return;
			}
			break;
		}
	}
	if (key == -1)
	{
		cout << "error cant find file" << endl;
		return;
	}
	string strt;
	stringstream buff;
	inode ti = inodes[key];
	long long dset = ti.d_set;
	string tf = readdisk(dset);
	cout << "----------disk file begin----------" << endl;
	cout << tf << endl;
	cout << "----------disk file end------------" << endl;


	string dir = basedir + nowusr.d_name + "/" + filename;
	ifstream readf(dir);
	
	buff << readf.rdbuf();
	strt = buff.str();
	cout << "----------file begin-----------" << endl;
	cout << strt << endl;
	readf.close();
	cout << "----------file end------------" << endl;
}
void myfwrite(string filename)//写文件
{
	if (nowusr.d_name == "")
	{
		cout << "please login" << endl;
		return;
	}
	int key = -1;
	for (set<int>::iterator it = nowusr.files_inodeid.begin(); it != nowusr.files_inodeid.end(); it++)
	{
		if (inodes[*it].name == filename)
		{
			key = *it;
			if (getPower(inodes[key], 2) == 0)
			{
				cout << "write fail,you dont have power" << endl;
				return;
			}
			break;
		}
	}
	if (key == -1)
	{
		cout << "error cant find file" << endl;
		return;
	}
	string data, strt;
	data = "";
	getline(cin, strt);
	getline(cin, strt);
	while (strt != "#")
	{
		data = data + strt;
		getline(cin, strt);
		if (strt != "#")data += "\n";
		else break;
	}
	string dir = basedir + nowusr.d_name + "/" + filename;
	ofstream fout(dir);
	fout << data;
	fout.close();
	inodes[key].size = data.size();
	freedisk(inodes[key].d_set);
	inodes[key].d_set=writedisk(data);
	cout << "write end" << endl;
}
void changeFPower(string usr,string filename,int power)//修改文件的权限，root用户方可使用
{
	if (nowusr.d_name != "root")
	{
		cout << "please login root" << endl;
		return;
	}
	int key = -1;
	for (set<int>::iterator it = directs[usr].files_inodeid.begin(); it != directs[usr].files_inodeid.end(); it++)
	{
		if (inodes[*it].name == filename)
		{
			key = *it;
			break;
		}
	}
	inodes[key].di_mode = power;
	if (key == -1)
	{
		cout << "error cant find file" << endl;
		return;
	}
	cout << "change power success" << endl;
}
void init()//初始化
{
	nowusr.d_name = ""; 
	buff[DBLOCK] = '\0';
	initmap();
}

int main()
{
	string in;
	init();
	cout << "--------1.createusr----------\n"
		<< "--------2.login--------------\n"
		<< "--------3.dir----------------\n"
		<< "--------4.create-------------\n"
		<< "--------5.delete-------------\n"
		<< "--------6.read---------------\n"
		<< "--------7.write--------------\n"
		<< "--------8.changepower--------\n"
		<< "--------9.exit---------------\n"
		<< "-------10.help---------------"
		<< endl;
	while (1)
	{
		savemap();
		cout << "\n--------input command:-------\n";
		cin >> in;
		if (in == "createusr")
		{
			string name, pwd;
			cin >> name >> pwd;
			createusr(name, pwd);
			continue;
		}
		if (in == "login")
		{
			string name, pwd;
			cin >> name >> pwd;
			login(name, pwd);
			continue;
		}
		if (in == "dir")
		{
			dir();
			continue;
		}
		if (in == "create")
		{
			string filename;
			cin >> filename;
			fcreate(filename);
			continue;
		}
		if (in == "delete")
		{
			string filename;
			cin >> filename;
			fdelete(filename);
			continue;
		}
		if (in == "read")
		{
			string filename;
			cin >> filename;
			myfread(filename);
			continue;
		}
		if (in == "write")
		{
			string filename;
			cin >> filename;
			myfwrite(filename);
			continue;
		}
		if (in == "changepower")
		{
			string filename;
			string usr;
			int qx;
			cin >> usr >> filename>>qx;
			changeFPower(usr, filename, qx);
			continue;

		}
		if (in == "exit")
		{
			savemap();
			break;
		}
		if (in == "help")
		{
			cout << "--------1.createusr----------\n"
				<< "--------2.login--------------\n"
				<< "--------3.dir----------------\n"
				<< "--------4.create-------------\n"
				<< "--------5.delete-------------\n"
				<< "--------6.read---------------\n"
				<< "--------7.write--------------\n"
				<< "--------8.exit---------------\n"
				<< "--------9.changepower--------\n"
				<< "-------10.help---------------"
				<< endl;
			continue;
		}
		cout << "------please check command------" << endl;
	}
}
/*测试
createusr root 123
createusr usr1 123
createusr usr2 123
dir
login usr1 123
create test.txt
dir
write test.txt
asdjfa
asfjn
masklf
#
dir
login root 123
changepower usr1 test.txt 400
login usr1 123
dir
read test.txt
write test.txt
delete test.txt
create deletetest.txt
dir
delete deletetest.txt
exit
*/